#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdbool.h>
#include <errno.h>

// ====================== 配置常量 ======================
#define MAX_STACK_SIZE 20
#define MAX_PATH_LEN 4096     // 支持长路径
#define MAX_LS_BUFFER 16384   // 大目录支持
#define MAX_COMMAND_LEN 512
#define MAX_COMPONENTS 256    // 路径组件限制

// ====================== 数据结构 ======================
typedef struct PathComponent {
    char *name;
    struct PathComponent *next;
} PathComponent;

typedef struct {
    char current_dir[MAX_PATH_LEN];   // 当前工作目录
    char root_dir[MAX_PATH_LEN];      // 沙箱根目录
    char *dir_stack[MAX_STACK_SIZE];  // 目录历史堆栈
    int stack_top;                    // 栈顶指针
} ClientSession;

// ====================== 辅助函数 ======================
// 安全字符串复制
void safe_strncpy(char *dest, const char *src, size_t n) {
    strncpy(dest, src, n);
    dest[n-1] = '\0';
}

// 安全连接字符串
void safe_strncat(char *dest, const char *src, size_t max_len) {
    size_t current_len = strlen(dest);
    size_t src_len = strlen(src);
    
    if (current_len + src_len >= max_len) {
        src_len = max_len - current_len - 1;
    }
    
    if (src_len > 0) {
        strncat(dest, src, src_len);
    }
}

// 路径规范化组件链表
void free_component_list(PathComponent *head) {
    PathComponent *current = head;
    while (current) {
        PathComponent *next = current->next;
        free(current->name);
        free(current);
        current = next;
    }
}

// ====================== 会话管理 ======================
// 初始化会话
void init_session(ClientSession *session, const char *root) {
    // 安全初始化结构体
    memset(session, 0, sizeof(ClientSession));
    
    // 处理根目录
    if (!root) root = "/tmp/default_root";
    
    // 直接复制根目录
    safe_strncpy(session->root_dir, root, MAX_PATH_LEN);
    
    // 确保以'/'结尾
    size_t len = strlen(session->root_dir);
    if (len > 0 && session->root_dir[len-1] != '/') {
        if (len < MAX_PATH_LEN - 1) {
            strncat(session->root_dir, "/", 2);
        }
    }
    
    // 设置当前目录
    safe_strncpy(session->current_dir, session->root_dir, MAX_PATH_LEN);
    
    session->stack_top = 0;
    printf("Initialized session with root: %s\n", session->root_dir);
}

// 清理会话资源
void free_session(ClientSession *session) {
    // 释放堆栈内存
    for (int i = 0; i < session->stack_top; i++) {
        if (session->dir_stack[i]) {
            free(session->dir_stack[i]);
            session->dir_stack[i] = NULL;
        }
    }
    session->stack_top = 0;
}

// ====================== 路径处理 ======================
// 路径规范化处理
bool normalize_path(ClientSession *session, const char *input_path, char *output_path) {
    // 输入验证
    if (!session || !input_path || !output_path) {
        fprintf(stderr, "Invalid arguments to normalize_path\n");
        return false;
    }
    
    // 处理特殊路径
    if (strcmp(input_path, "~") == 0 || strcmp(input_path, "/") == 0) {
        safe_strncpy(output_path, session->root_dir, MAX_PATH_LEN);
        return true;
    }
    
    // 创建临时路径缓冲区
    char *temp_path = (char *)malloc(MAX_PATH_LEN * 2);
    if (!temp_path) {
        perror("malloc failed for temp_path");
        return false;
    }
    memset(temp_path, 0, MAX_PATH_LEN * 2);
    
    // 构造初始路径
    if (input_path[0] == '/') {
        snprintf(temp_path, MAX_PATH_LEN * 2 - 1, "%s%s", session->root_dir, input_path);
    } else {
        // 确保当前目录有效
        if (session->current_dir[0] == '\0') {
            safe_strncpy(session->current_dir, session->root_dir, MAX_PATH_LEN);
        }
        snprintf(temp_path, MAX_PATH_LEN * 2 - 1, "%s/%s", session->current_dir, input_path);
    }
    
    // 使用链表存储路径组件
    PathComponent *head = NULL;
    PathComponent *tail = NULL;
    int comp_count = 0;
    
    // 分割路径组件
    char *saveptr;
    char *token = strtok_r(temp_path, "/", &saveptr);
    while (token != NULL) {
        if (strcmp(token, ".") == 0) {
            // 忽略当前目录
        } else if (strcmp(token, "..") == 0) {
            // 回退上级目录
            if (head) {
                PathComponent *prev = head;
                if (prev->next) {
                    while (prev->next != tail) prev = prev->next;
                    free(tail->name);
                    free(tail);
                    tail = prev;
                    tail->next = NULL;
                } else {
                    free(head->name);
                    free(head);
                    head = tail = NULL;
                }
                comp_count--;
            }
        } else {
            // 添加新组件
            PathComponent *comp = (PathComponent *)malloc(sizeof(PathComponent));
            if (!comp) {
                perror("malloc failed for PathComponent");
                break;
            }
            
            comp->name = strdup(token);
            if (!comp->name) {
                free(comp);
                perror("strdup failed");
                break;
            }
            
            comp->next = NULL;
            
            if (!head) {
                head = tail = comp;
            } else {
                tail->next = comp;
                tail = comp;
            }
            comp_count++;
            
            if (comp_count > MAX_COMPONENTS) {
                fprintf(stderr, "Too many path components: %d\n", comp_count);
                break;
            }
        }
        token = strtok_r(NULL, "/", &saveptr);
    }
    
    // 重建路径
    safe_strncpy(output_path, session->root_dir, MAX_PATH_LEN);
    size_t current_len = strlen(output_path);
    
    PathComponent *current = head;
    while (current) {
        size_t comp_len = strlen(current->name);
        
        // 检查空间
        if (current_len + comp_len + 2 > MAX_PATH_LEN) {
            fprintf(stderr, "Path too long: %s\n", output_path);
            break;
        }
        
        // 添加分隔符
        if (output_path[current_len-1] != '/') {
            output_path[current_len++] = '/';
            output_path[current_len] = '\0';
        }
        
        // 添加组件
        strcat(output_path, current->name);
        current_len += comp_len;
        
        PathComponent *next = current->next;
        free(current->name);
        free(current);
        current = next;
    }
    
    // 确保以'/'结尾
    if (current_len > 0 && output_path[current_len-1] != '/') {
        if (current_len < MAX_PATH_LEN - 1) {
            strcat(output_path, "/");
        }
    }
    
    // 清理
    free(temp_path);
    
    // 沙箱验证
    if (strncmp(output_path, session->root_dir, strlen(session->root_dir)) != 0) {
        fprintf(stderr, "Path escapes sandbox: %s\n", output_path);
        return false;
    }
    
    return true;
}

// ====================== 命令实现 ======================
// 压栈：保存当前目录
bool push_dir(ClientSession *session) {
    if (session->stack_top >= MAX_STACK_SIZE) {
        fprintf(stderr, "Directory stack overflow\n");
        return false;
    }
    
    // 确保当前目录有效
    if (session->current_dir[0] == '\0') {
        fprintf(stderr, "Cannot push empty directory\n");
        return false;
    }
    
    session->dir_stack[session->stack_top] = strdup(session->current_dir);
    if (session->dir_stack[session->stack_top] == NULL) {
        perror("strdup failed");
        return false;
    }
    
    session->stack_top++;
    return true;
}

// 弹栈：获取历史目录
char *pop_dir(ClientSession *session) {
    if (session->stack_top <= 0) {
        fprintf(stderr, "Directory stack underflow\n");
        return NULL;
    }
    
    session->stack_top--;
    char *dir = session->dir_stack[session->stack_top];
    session->dir_stack[session->stack_top] = NULL;  // 防止双重释放
    return dir;
}

// 处理cd命令
bool handle_cd(ClientSession *session, const char *path) {
    if (path == NULL || path[0] == '\0') {
        path = "~";  // 默认到根目录
    }
    
    // 特殊命令：cd - (返回上一级)
    if (strcmp(path, "-") == 0) {
        if (session->stack_top == 0) {
            fprintf(stderr, "No previous directory\n");
            return false;
        }
        
        char *prev_dir = pop_dir(session);
        if (!prev_dir) return false;
        
        // 保存当前目录到堆栈
        if (!push_dir(session)) {
            free(prev_dir);
            return false;
        }
        
        // 更新当前目录
        safe_strncpy(session->current_dir, prev_dir, MAX_PATH_LEN);
        free(prev_dir);
        return true;
    }
    
    char target[MAX_PATH_LEN] = {0};
    char old_dir[MAX_PATH_LEN] = {0};
    safe_strncpy(old_dir, session->current_dir, MAX_PATH_LEN);
    
    // 规范化路径
    if (!normalize_path(session, path, target)) {
        fprintf(stderr, "Invalid path: %s\n", path);
        return false;
    }

    // 保存当前目录到堆栈
    if (!push_dir(session)) return false;
    
    // 更新当前目录
    safe_strncpy(session->current_dir, target, MAX_PATH_LEN);
    return true;
}

// 处理pwd命令
const char *handle_pwd(ClientSession *session) {
    static char result[MAX_PATH_LEN] = {0};
    
    // 安全处理空当前目录
    if (session->current_dir[0] == '\0') {
        safe_strncpy(session->current_dir, session->root_dir, MAX_PATH_LEN);
    }
    
    // 返回相对于根目录的路径
    size_t root_len = strlen(session->root_dir);
    const char *relative_path = session->current_dir + root_len;
    
    // 如果当前在根目录，返回"/"
    if (*relative_path == '\0') {
        safe_strncpy(result, "/", MAX_PATH_LEN);
        return result;
    }
    
    // 安全复制
    safe_strncpy(result, relative_path, MAX_PATH_LEN);
    return result;
}

// 处理ls命令
char *handle_ls(ClientSession *session) {
    // 安全处理空当前目录
    if (session->current_dir[0] == '\0') {
        safe_strncpy(session->current_dir, session->root_dir, MAX_PATH_LEN);
    }
    
    DIR *dir = opendir(session->current_dir);
    if (!dir) {
        fprintf(stderr, "Cannot open directory: %s\n", session->current_dir);
        return NULL;
    }

    struct dirent *entry;
    char *result = (char *)calloc(MAX_LS_BUFFER, 1);
    if (!result) {
        perror("malloc failed");
        closedir(dir);
        return NULL;
    }
    
    char temp[256];
    size_t remaining = MAX_LS_BUFFER - 1;
    int count = 0;

    while ((entry = readdir(dir)) != NULL) {
        // 跳过隐藏文件
        if (entry->d_name[0] == '.') continue;
        
        // 获取文件类型标记
        char type = ' ';
        if (entry->d_type == DT_DIR) {
            type = '/';
        } else if (entry->d_type == DT_LNK) {
            type = '@';
        } else if (entry->d_type == DT_FIFO) {
            type = '|';
        } else if (entry->d_type == DT_SOCK) {
            type = '=';
        }
        
        // 安全格式化
        int needed = snprintf(temp, sizeof(temp), "%-24s%c\n", entry->d_name, type);
        if (needed < 0 || (size_t)needed >= remaining) {
            break;  // 缓冲区不足
        }
        
        strcat(result, temp);
        remaining -= needed;
        count++;
    }
    closedir(dir);
    
    if (count == 0) {
        strcpy(result, "No files or directories\n");
    }
    
    return result;  // 调用者需free()
}

// 处理mkdir命令
bool handle_mkdir(ClientSession *session, const char *path) {
    if (path == NULL || path[0] == '\0') {
        fprintf(stderr, "Missing directory name\n");
        return false;
    }
    
    char target[MAX_PATH_LEN] = {0};
    
    // 规范化路径
    if (!normalize_path(session, path, target)) {
        fprintf(stderr, "Invalid path: %s\n", path);
        return false;
    }
    
    // 移除结尾的斜杠（mkdir需要）
    size_t len = strlen(target);
    if (len > 0 && target[len-1] == '/') {
        target[len-1] = '\0';
    }
    
    // 检查目录是否已存在
    struct stat st;
    if (stat(target, &st) == 0) {
        if (S_ISDIR(st.st_mode)) {
            fprintf(stderr, "Directory already exists: %s\n", target);
        } else {
            fprintf(stderr, "Path exists but is not a directory: %s\n", target);
        }
        return false;
    }
    
    // 创建目录
    if (mkdir(target, 0700) != 0) {
        fprintf(stderr, "mkdir failed for %s: %s\n", target, strerror(errno));
        return false;
    }
    
    return true;
}

// 处理rmdir命令
bool handle_rmdir(ClientSession *session, const char *path) {
    if (path == NULL || path[0] == '\0') {
        fprintf(stderr, "Missing directory name\n");
        return false;
    }
    
    char target[MAX_PATH_LEN] = {0};
    
    // 规范化路径
    if (!normalize_path(session, path, target)) {
        fprintf(stderr, "Invalid path: %s\n", path);
        return false;
    }
    
    // 移除结尾的斜杠
    size_t len = strlen(target);
    if (len > 0 && target[len-1] == '/') {
        target[len-1] = '\0';
    }
    
    // 检查目录是否存在
    struct stat st;
    if (stat(target, &st) != 0) {
        fprintf(stderr, "Directory does not exist: %s\n", target);
        return false;
    }
    
    // 检查是否为目录
    if (!S_ISDIR(st.st_mode)) {
        fprintf(stderr, "Not a directory: %s\n", target);
        return false;
    }
    
    // 检查目录是否为空
    DIR *dir = opendir(target);
    if (!dir) {
        fprintf(stderr, "Cannot open directory: %s\n", target);
        return false;
    }
    
    struct dirent *entry;
    int file_count = 0;
    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
            file_count++;
            break;
        }
    }
    closedir(dir);
    
    if (file_count > 0) {
        fprintf(stderr, "Directory not empty: %s\n", target);
        return false;
    }
    
    // 删除空目录
    if (rmdir(target) != 0) {
        fprintf(stderr, "rmdir failed for %s: %s\n", target, strerror(errno));
        return false;
    }
    
    return true;
}

// ====================== 命令处理器 ======================
void process_command(ClientSession *session, const char *command) {
    if (!command || !session) return;
    
    char cmd[32] = {0};
    char path[MAX_PATH_LEN] = {0};
    
    // 安全解析命令
    const char *space_pos = strchr(command, ' ');
    if (space_pos) {
        // 提取命令部分
        size_t cmd_len = space_pos - command;
        if (cmd_len >= sizeof(cmd)) cmd_len = sizeof(cmd) - 1;
        strncpy(cmd, command, cmd_len);
        cmd[cmd_len] = '\0';
        
        // 提取路径部分
        const char *path_start = space_pos + 1;
        while (*path_start == ' ') path_start++;  // 跳过空格
        
        safe_strncpy(path, path_start, MAX_PATH_LEN);
    } else {
        safe_strncpy(cmd, command, sizeof(cmd));
    }
    
    // 处理命令
    if (strcmp(cmd, "cd") == 0) {
        if (!handle_cd(session, path)) {
            printf("ERROR: Directory change failed\n");
        } else {
            printf("Current directory: %s\n", handle_pwd(session));
        }
        
    } else if (strcmp(cmd, "pwd") == 0) {
        printf("Current directory: %s\n", handle_pwd(session));
        
    } else if (strcmp(cmd, "ls") == 0) {
        char *list = handle_ls(session);
        if (list) {
            printf("Directory listing:\n%s", list);
            free(list);
        } else {
            printf("ERROR: Failed to list directory\n");
        }
        
    } else if (strcmp(cmd, "mkdir") == 0) {
        if (handle_mkdir(session, path)) {
            printf("SUCCESS: Directory created\n");
        } else {
            printf("ERROR: Failed to create directory\n");
        }
        
    } else if (strcmp(cmd, "rmdir") == 0) {
        if (handle_rmdir(session, path)) {
            printf("SUCCESS: Directory removed\n");
        } else {
            printf("ERROR: Failed to remove directory\n");
        }
        
    } else {
        printf("ERROR: Unknown command '%s'\n", cmd);
    }
}

// ====================== 测试函数 ======================
void test_path_normalization(ClientSession *session) {
    printf("\n=== Testing Path Normalization ===\n");
    
    struct {
        const char *input;
        const char *expected;
    } tests[] = {
        {"", session->root_dir},
        {".", session->root_dir},
        {"..", session->root_dir},
        {"../..", session->root_dir},
        {"documents", "documents/"},
        {"/projects", "projects/"},
        {"documents/../projects", "projects/"},
        {"~/path", "path/"},
        {"/path/with/../subdir", "path/subdir/"},
        {NULL, NULL}
    };
    
    char output[MAX_PATH_LEN];
    
    for (int i = 0; tests[i].input; i++) {
        memset(output, 0, sizeof(output));
        bool result = normalize_path(session, tests[i].input, output);
        
        // 提取相对路径
        const char *relative = output + strlen(session->root_dir);
        
        printf("Test '%s': %s -> %s [%s]\n", 
               tests[i].input, 
               result ? "OK" : "FAIL",
               relative,
               strcmp(relative, tests[i].expected) == 0 ? "MATCH" : "MISMATCH");
    }
}

int main(int argc, char *argv[]) {
    const char *root_path = "/home/muridae/DraftsJ/TestsJ/Private_protocol_file_management_server_projectJ/PPFMSPJ/Tests1J/tmp/safe_root";
    
    // 允许命令行指定根路径
    if (argc > 1) {
        root_path = argv[1];
    }
    
    printf("Starting server with root: %s\n", root_path);
    
    ClientSession session;
    init_session(&session, root_path);
    
    // 创建测试环境
    mkdir(session.root_dir, 0700);
    mkdir(strcat(strdup(session.root_dir), "documents"), 0700);
    mkdir(strcat(strdup(session.root_dir), "projects"), 0700);
    
    printf("--- Starting session in: %s ---\n", handle_pwd(&session));
    
    // 测试路径规范化
    test_path_normalization(&session);
    
    // 测试命令序列
    printf("\n=== Testing Commands ===\n");
    process_command(&session, "pwd");
    process_command(&session, "ls");
    process_command(&session, "cd documents");
    process_command(&session, "pwd");
    process_command(&session, "cd ..");
    process_command(&session, "cd -");
    process_command(&session, "mkdir new_folder");
    process_command(&session, "ls");
    process_command(&session, "rmdir new_folder");
    process_command(&session, "cd /");
    process_command(&session, "pwd");
    
    printf("\nSession ended successfully\n");
    free_session(&session);
    return 0;
}
